/* SmartPointerI.h
 * 
 *  Author          : Alexander J. Yee
 *  Date Created    : 05/28/2017
 *  Last Modified   : 05/28/2017
 * 
 *      A lightweight smart pointer for incomplete types.
 * 
 */

#pragma once
#ifndef ymp_Memory_SmartPointerI_H
#define ymp_Memory_SmartPointerI_H
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//  Dependencies
namespace ymp{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
enum SmartPointerToken{
    MAKE,
};
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
template <typename Type>
class SmartPointerI{
public:
    //  Rule of 5

    ~SmartPointerI();

    SmartPointerI(SmartPointerI&& x) noexcept
        : m_ptr(x.m_ptr)
    {
        x.m_ptr = nullptr;
    }
    void operator=(SmartPointerI&& x) noexcept{
        clear();
        m_ptr = x.m_ptr;
        x.m_ptr = nullptr;
    }

    SmartPointerI(const SmartPointerI& x) = delete;
    void operator=(const SmartPointerI& x) = delete;


public:
    //  Construction

    SmartPointerI() noexcept
        : m_ptr(nullptr)
    {}

    template <class... Args>
    SmartPointerI(SmartPointerToken, Args&&... args);

    template <typename T>
    SmartPointerI(SmartPointerI<T> ptr)
        : m_ptr(ptr.m_ptr)
    {
        ptr.m_ptr = nullptr;
    }

    void clear() noexcept;

    template <class... Args>
    void reset(Args&&... args);

    Type* release() noexcept{
        Type* ptr = m_ptr;
        m_ptr = nullptr;
        return ptr;
    }


public:
    const Type* operator->() const{
        return m_ptr;
    }
    Type* operator->(){
        return m_ptr;
    }

    operator const Type*() const{
        return m_ptr;
    }
    operator Type*(){
        return m_ptr;
    }

private:
    Type* m_ptr;

    template <typename T> friend class SmartPointerI;
};
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
}
#endif
